import {
  computed,
  ComputedRef,
  onMounted,
  onUnmounted,
  provide,
  Ref,
} from 'vue'
import { useTimeline } from './timeline'
import { DndComposition, useDnd } from './dnd'
import { useShortcuts } from '@/composables/shortcuts'
import { Track } from '@/core/track'
import { useActions } from '@/composables/actions'
import { draggingTypeMap } from '@/constants'
import { secToTime } from '@/lib/util'
import {
  getPositionByTime,
  getTimeByPosition,
  getUnhandlePosition,
  splitClip,
} from '@/console/storyboard'

export type StoryboardComposition = {
  currentTime: Ref<number>
  updateCurrentTime: (x: number) => void
  duration: Ref<number>
  storyboard: ComputedRef<Track>
  displayCurrentTime: ComputedRef<string>
  currentTimeLeft: ComputedRef<string>
  marginLeftClassName: ComputedRef<string>
  handleSliderMouseDown: (e: MouseEvent) => void
  draggerHandler: (e: { x: number; y: number; finished: boolean }) => void
  addMark: () => void
  handleSplitClick: () => void
} & DndComposition

export function useStoryboard(): StoryboardComposition {
  const { currentTime, updateCurrentTime, duration, storyboard } = useTimeline()
  const { dragging, draggingType, draggingOverIndex } = useDnd(storyboard.value)
  const { bind: bindShorcuts, unbind: unbindShortcuts } = useShortcuts()
  const { bind: bindActions, unbind: unbindActions } = useActions(
    currentTime,
    storyboard
  )

  provide('storyboard', storyboard.value)
  onMounted(() => {
    bindShorcuts()
    bindActions()
  })

  onUnmounted(() => {
    unbindShortcuts()
    unbindActions()
  })

  const displayCurrentTime = computed(() => secToTime(currentTime.value))

  const currentTimeLeft = computed(() => {
    let total = 0
    let offset = 35
    for (let clip of storyboard.value.clips) {
      total += clip.duration
      if (total > currentTime.value) {
        offset += Math.round(
          ((currentTime.value - total + clip.duration) / clip.duration) * 240
        )
        break
      }
      offset += 240
    }
    return `${offset}px`
  })
  const marginLeftClassName = computed(() =>
    draggingType.value === draggingTypeMap.MOVE_CLIP
      ? 'makespace-70'
      : 'makespace-240'
  )
  const handleSliderMouseDown = (e: MouseEvent) => {
    const pos = Math.max(e.offsetX - 35, 0)
    const newTime = getTimeByPosition(storyboard.value, pos)
    updateCurrentTime(newTime)
  }

  const draggerHandler = (e: { x: number; y: number; finished: boolean }) => {
    const nowPos = getPositionByTime(storyboard.value, currentTime.value)
    const newPos = e.x + nowPos
    const newTime = getTimeByPosition(storyboard.value, newPos)
    updateCurrentTime(newTime)
    return {
      x: getUnhandlePosition(storyboard.value, newPos),
      y: 0,
    }
  }

  const addMark = () => {}
  const handleSplitClick = () => {
    splitClip(storyboard.value, currentTime.value)
  }

  return {
    // timeline
    currentTime,
    updateCurrentTime,
    duration,
    storyboard,
    // dnd
    dragging,
    draggingType,
    draggingOverIndex,
    // ui
    displayCurrentTime,
    currentTimeLeft,
    marginLeftClassName,
    handleSliderMouseDown,
    draggerHandler,

    addMark,
    handleSplitClick,
  }
}
